<?php

namespace App\App\Services;

use App\Contracts\Services\Storage\StorageService as StorageServiceContract;
use Symfony\Component\HttpFoundation\File\UploadedFile;

class StorageService
{
    /**
     * @var StorageServiceContract
     */
    private $storageService;

    /**
     * @param StorageServiceContract $storageService
     */
    public function __construct(StorageServiceContract $storageService)
    {
        $this->storageService = $storageService;
    }

    /**
     * check whether the url is tmp
     *
     * @param $url
     *
     * @return bool
     */
    public function isTmp($url)
    {
        return starts_with($url, 'http') && str_contains($url, "/tmp/");
    }

    /**
     * store given file as temporary image
     *
     * @param string $file                                file path.   this file MUST exist
     * @param array  $options                             options
     *                                                    - url_only   when set to true(default), only identifier
     *                                                    of the file will be returned.
     *                                                    - bucket     (optional)which bucket to store the file
     *                                                    - ext        (Optional) extension of the file. it's possible
     *                                                    that $file does not have extension suffix.
     *                                                    - mime       (optional) mime of the file.
     *
     * @return string|array     - if the returned value is a string, it's the identifier
     *                          of the file.
     *                          - if the returned value is an array, identifier of the
     *                          file should be included, which is keyed by 'id'.
     *
     * @throws \Exception       network/storage exception
     */
    public function storeAsTmpImage($file, array $options = [])
    {

        $ext = $this->guessExt($file, true);
        if ($ext) {
            array_set($options, 'ext', $ext);
        }
        //处理旋转图片
        if ($ext == 'jpg') {
            $path = strval($file);
            $info = getimagesize($path);
            if ($info) {
                $this->image_fix_orientation($path);
            }
        }

        array_set($options, 'prefix', 'tmp/' . date('Ymd') . '/' . date('H') . '/');
        return $this->parseResult(
            $this->store($file, $options),
            $options
        );
    }

    /**
     * 上传图片旋转
     *
     * @param $path
     */
    protected function image_fix_orientation($path)
    {
        $image = imagecreatefromjpeg($path);
        $exif = @exif_read_data($path);
        if ($exif !== false && !empty($exif['Orientation'])) {
            switch ($exif['Orientation']) {
                case 3:
                    $image = imagerotate($image, 180, 0);
                    break;
                case 6:
                    $image = imagerotate($image, -90, 0);
                    break;
                case 8:
                    $image = imagerotate($image, 90, 0);
                    break;
            }
            imagejpeg($image, $path);
        }
    }

    /**
     * store given file as image
     *
     * @param       $file                    |string      file path:this file MUST exist; string:this url is tmp url
     * @param array $options                 options
     *                                       - url_only   when set to true(default), only identifier
     *                                       of the file will be returned.
     *                                       - url        (optional) special identifier
     *                                       - bucket     (optional) which bucket to store the file
     *                                       - ext        (optional) extension of the file. it's possible
     *                                       that $file does not have extension suffix.
     *                                       - mime       (optional) mime of the file.
     *                                       - prefix     (optional) prefix of object
     *
     * @return string|array     - if the returned value is a string, it's the identifier(url)
     *                          of the file.
     *                          - if the returned value is an array, identifier of the
     *                          file should be included, which is keyed by 'url id'.
     *
     * @throws \Exception       network/storage exception
     */
    public function storeAsImage($file, array $options = [])
    {
        if (empty($file)) {
            return '';
        }
        if ($ext = $this->guessExt($file, true)) {
            array_set($options, 'ext', $ext);
        }
        array_set($options, 'prefix', date('Ymd') . '/' . date('H') . '/');
        //if (is_string($file) && $this->isTmp($file)) {
            if (is_string($file)) {
            $result = $this->copy($file, $options);
        } else {
            $result = $this->store($file, $options);
        }

        return $this->parseResult(
            $result,
            $options
        );
    }

   public function tomedia($url)
    {
        if (empty($url)) {
            return $url;
        }

        return $this->storageService->toHttpUrl($url);
    }

    private function guessExt($file, $image = false)
    {
        if ($image) {
            // UploadedFile implements __toString() method, and this is the only
            // way to get its full path
            $path = strval($file);

            $info = getimagesize($path);

            if (!$info) {
                return false;
            }

            return ($info[2] == IMAGETYPE_PNG) ? 'png' : 'jpg';
        }
        if ($file instanceof UploadedFile) {
            return $file->getClientOriginalExtension();
        }

        return null;
    }

    private function store($file, array $options = [])
    {
        if (!is_file($file)) {
            throw new \Exception('file is invalid');
        }
        return $this->storageService->store($file, $options);
    }

    private function copy($url, array $options = [])
    {
        return $this->storageService->copy(
            $this->storageService->toSchemaUrl($url),
            $options
        );
    }

    private function parseResult($result, array $options = [])
    {
        if (array_get($options, 'url_only', true)) {
            $http_url = $this->storageService->toHttpUrl($result);

            return [
                'url'        => $http_url,
                'original'   => $result,
                'attachment' => $this->storageService->toSchemaUrl($http_url),
            ];
        }
        $result['id'] = $this->storageService->toHttpUrl($result);

        return $result;
    }

    /**
     * remove the stored file by url
     *
     * @param string $url                       url of the file to be removed
     * @param array  $options                   options.
     *                                          - inspect  when set to true(default false), no inspection
     *                                          will be performed to check the file's existence.
     *                                          - bucket   (optional) which bucket to remove the file
     *
     * @return void    if there's no exception, the removal succeeded.
     */
    public function remove($url, array $options = [])
    {
        $this->storageService->remove(
            $this->storageService->toSchemaUrl($url, $options),
            $options
        );
    }
}
